package cn.tedu.charging.device.dao.impl;

import cn.tedu.charging.device.dao.repository.StationCacheTemplateRepository;
import cn.tedu.charging.device.pojo.po.StationCanalPO;
import cn.tedu.charging.device.pojo.po.StationInfoWrapper;
import cn.tedu.charging.device.pojo.po.StationPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.BoundGeoOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 位置信息和基本信息建议分开存  基本信息可以复用
 *
 * 基本信息 可以通过什么类型存 ? 更加合理
 * String
 * Hash独享 一个站 一个hash
 * Hash共享 所有站 一个hash
 *
 *
 *
 */
@Slf4j
@Repository("GEOANDNOSHAREHASH")
public class StationCacheTemplateGEOAndNoShareHashImpl
        extends AbstractStationCacheTemplate implements StationCacheTemplateRepository {



    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * Redis K V  Map<String,Object>
     * 基本类型  Redis 的 value V
     * String Map<String,String>     key 站id value 站信息
     * List   Map<String,List<Object>>   key 站id value List size 1 里面只放一个 id对应的站信息
     * Hash   Map<String,Map<String,Object>>
     *
     *      key: 站id ?不一定
     *      Map<String,Object> key: 站id?不一定  Object:基本信息
     *
     *      A 每个站 一个map
     *      key: 站id
     *      Map<String,Object> key: 属性名(名称)  Object: 属性值(好又快充电站)
     *
     *      B  所有的站 在一个大map里
     *      key: all_station_infos
     *      Map<String,Object> key: 站id  Object: 基本信息
     *
     *      选A?  选B ? 为什么?
     *
     *
     * Set    Map<String,HashSet<Object>>  key 站id value Set size 1 里面只放一个 id对应的站信息
     * Zset   Map<String,TreeSet<Object>>  key 站id value TreeSet size 1 里面只放一个 id对应的站信息
     * GEO    Map<String,GEO<Object>>  zset
     *
     *
     */





  /*  *//**
     * 保存位置信息 到 GEO
     * 同时保存 member为 位置对应的站id
     * @param stationPOs
     *//*
    public void saveGEOByRedisGEOAndMemberIsId(List<StationPO> stationPOs) {
        Map<Integer,Point> stationPOMap = new HashMap<>();
        for (StationPO stationPO : stationPOs) {
            //获取经度
            BigDecimal stationLng = stationPO.getStationLng();
            //获取纬度
            BigDecimal stationLat = stationPO.getStationLat();
            //通过 经纬度 构建RedisGEO 中的点 Point
            Point point = new Point(Double.valueOf(stationLng.toEngineeringString()),
                    Double.parseDouble(stationLat.toEngineeringString()));
            stationPOMap.put(stationPO.getId(),point);
        }
        BoundGeoOperations stations = redisTemplate.boundGeoOps("stations");
        stations.add(stationPOMap);
    }*/


    /**
     * 通过 Redis的 Hash 类型 保存场站的基本信息
     * 共享 所有的站在一个map
     * key all 固定
     * hashkey 站id
     * value 站信息
     * @param stationPOs
     */
    @Override
    public void save(List<StationPO> stationPOs){
        saveGEOByRedisGEOAndMemberIsId(stationPOs);
        for (StationPO stationPO : stationPOs) {
            saveStationInfoByHashNoShare(stationPO);
        }
    }

    @Override
    public List<StationInfoWrapper> search(Double longitude, Double latitude, Double distance) {
        return super.search(longitude,latitude,distance);
    }

    @Override
    public void delete(StationCanalPO stationCanalPO) {
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.remove("stations",stationCanalPO);

        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete("station_info_hash_no_share_" + stationCanalPO.getId(),"stationName");
    }

    @Override
    public void add(StationCanalPO stationCanalPO) {
        log.debug("加点");
        BoundGeoOperations stations = redisTemplate.boundGeoOps("stations");
        Point point = new Point(Double.valueOf(stationCanalPO.getStationLng().toEngineeringString()),
                Double.valueOf(stationCanalPO.getStationLat().toEngineeringString()));
        stations.add(point,stationCanalPO.getId());

        log.debug("加no hash");
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.put("station_info_hash_no_share_" + stationCanalPO.getId(),"stationName",stationCanalPO.getStationName());
    }

    @Override
    public StationPO getStationInfoById(String stationId) {
        HashOperations hashOperations = redisTemplate.opsForHash();
        String key = "station_info_hash_no_share_" + stationId;
        //key StationPO 的属性名 value 是StationPO 的属性值
        //Object o = hashOperations.get(key, "stationName");
        //entries 通过大key获取 里面的小map
        Map<String,Object> entries = hashOperations.entries(key);
        StationPO stationPO = (StationPO) entries.get("stationPO");
        return stationPO;
    }

    /**
     * 通过 Redis的String 类型 保存场站的基本信息
     * 不共享 一个站 一个map
     * @param stationPO
     */
    private void saveStationInfoByHashNoShare(StationPO stationPO){
        HashOperations hashOperations = redisTemplate.opsForHash();
        String key = "station_info_hash_no_share_" + stationPO.getId();
        //key StationPO 的属性名 value 是StationPO 的属性值
        Map<String,Object> smallMap = new HashMap<>();
        smallMap.put("stationPO",stationPO.getStationName());
        //如果有多个属性值,用putAll 一次命令搞定 性能相对较好
        hashOperations.putAll(key,smallMap);
        //如果有多个属性值 ,多次命令执行 性能相对较差
        hashOperations.put(key,"stationPO",stationPO);
    }

    @Override
    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }
}
